#include <stdio.h>
#include <stdlib.h>
#include "lv_drv_conf.h"
#include "board.h"
#include "lv_drivers/common/pwm.h"

/* I2C MFP */
uint32_t i2c_pinmux_cfgs[4][4] = {
    {   /* CI2C 0 */
        MFP_REG(GPIO_49) | MFP_DRIVE_MEDIUM | MFP_PULL_HIGH | MFP_AF1,
        MFP_REG(GPIO_50) | MFP_DRIVE_MEDIUM | MFP_PULL_HIGH | MFP_AF1,
        MFP_EOC
    },
    {   /* CI2C 1 */
        MFP_REG(GPIO_10) | MFP_DRIVE_MEDIUM | MFP_PULL_HIGH | MFP_AF1,
        MFP_REG(GPIO_11) | MFP_DRIVE_MEDIUM | MFP_PULL_HIGH | MFP_AF1,
        MFP_EOC
    },
    {   /* CI2C 2 */
        MFP_REG(GPIO_72) | MFP_DRIVE_MEDIUM | MFP_PULL_HIGH | MFP_AF2,
        MFP_REG(GPIO_73) | MFP_DRIVE_MEDIUM | MFP_PULL_HIGH | MFP_AF2,
        MFP_EOC
    },
    {   /* CI2C 3 */
        MFP_REG(GPIO_USIM2_UCLK) | MFP_DRIVE_MEDIUM | MFP_PULL_HIGH | MFP_AF6,
        MFP_REG(GPIO_USIM2_UIO) | MFP_DRIVE_MEDIUM | MFP_PULL_HIGH | MFP_AF6,
        MFP_EOC
    },
};

void pmic_vibrator_on(void)
{
    NingboVibratorEnable();
}

void pmic_vibrator_off(void)
{
    NingboVibratorDisable();
}

uint32_t tick_to_ms(uint32_t tick)
{
    uint32_t delta = lv_get_ticks_per_second() / 1000;
    return tick / delta;
}

void board_power_off(int type)
{
    if (SIM_COUNT == 2) {
        Ril_MM_Request_Shutdown(RIL_SIM_2, type);
    }
    Ril_MM_Request_Shutdown(RIL_SIM_1, type);
}

int startup_silent_reset(void)
{
    return isSysRestartByError();
}

__attribute__((__used__)) static const uint32_t pm812_bg_mfp_cfgs[] = {
    MFP_REG(GPIO_77) | MFP_AF0 | MFP_DRIVE_MEDIUM | MFP_PULL_LOW | MFP_LPM_EDGE_NONE,
    MFP_EOC /*End of configuration, must have */
};

__attribute__((__used__)) static const uint32_t pm802_bg_mfp_cfgs[] = {
    MFP_REG(GPIO_84) | MFP_AF0 | MFP_DRIVE_MEDIUM | MFP_PULL_LOW | MFP_LPM_EDGE_NONE,
    MFP_EOC /*End of configuration, must have */
};

#if USE_PWM
/* CraneG evb backlight config */
#ifdef USE_WATCH_LITE
#define LEDK_PWM                          GPIO_126
#define LEDK_PWM_GPIO                     GPIO126
#define PWM_DEV_BACKLIGHT                 PWM_DEV_0
#define PERIOD_NS                         33333 /* 30KHz */
#define LEVEL_MAX                         5

__attribute__((__used__)) static const uint32_t pwm_bg_mfp_cfgs[] = {
    MFP_REG(LEDK_PWM) | MFP_AF1 | MFP_DRIVE_MEDIUM | MFP_PULL_HIGH,
    MFP_EOC /*End of configuration, must have */
};

__attribute__((__used__)) static const uint32_t pwm_bgoff_mfp_cfgs[] = {
    MFP_REG(LEDK_PWM) | MFP_AF2 | MFP_DRIVE_MEDIUM | MFP_PULL_LOW,
    MFP_EOC /*End of configuration, must have */
};
#else
#define LEDK_PWM                          GPIO_31
#define LEDK_PWM_GPIO                     GPIO31
#define PWM_DEV_BACKLIGHT                 PWM_DEV_0
#define PERIOD_NS                         33333 /* 30KHz */
#define LEVEL_MAX                         5

__attribute__((__used__)) static const uint32_t pwm_bg_mfp_cfgs[] = {
    MFP_REG(LEDK_PWM) | MFP_AF2 | MFP_DRIVE_MEDIUM | MFP_PULL_HIGH,
    MFP_EOC /*End of configuration, must have */
};

__attribute__((__used__)) static const uint32_t pwm_bgoff_mfp_cfgs[] = {
    MFP_REG(LEDK_PWM) | MFP_AF0 | MFP_DRIVE_MEDIUM | MFP_PULL_LOW,
    MFP_EOC /*End of configuration, must have */
};
#endif
#endif

int pmic_get_type(void)
{
    int type = PM_813;

    if(PMIC_IS_PM812()) {
        type = PM_812;
    } else if(PMIC_IS_PM813()) {
        type = PM_813;
    } else if(PMIC_IS_PM802()) {
        type = PM_802;
    } else if(PMIC_IS_PM803()) {
        type = PM_803;
    }
    return type;
}

void pmic_init(void)
{
    int pmic_type = pmic_get_type();
    if(pmic_type == PM_812) {
        printf("PMIC: 812~\n");
    } else if(pmic_type == PM_813) {
        printf("PMIC: 813~\n");
    } else if(pmic_type == PM_802) {
        printf("PMIC: 802~\n");
    } else if(pmic_type == PM_803) {
        printf("PMIC: 803~\n");
    } else {
        printf("PMIC: unknown!! \n");
    }
}

static void backlight_pwm(unsigned level)
{
#if USE_PWM
    int duty_ns, period_ns;

    if (level > 5) {
        level = 5;
    }

    if (level == 0) {
        gpio_set_direction(LEDK_PWM_GPIO, GPIO_OUT);
        gpio_output_set(LEDK_PWM_GPIO, 0);
        mfp_config((unsigned int *)pwm_bgoff_mfp_cfgs);

        lv_pwm_disable(PWM_DEV_BACKLIGHT);
    } else {
        period_ns = PERIOD_NS;
        duty_ns = period_ns / (LEVEL_MAX - level + 1);
        lv_pwm_enable(PWM_DEV_BACKLIGHT, duty_ns, period_ns);

        mfp_config((unsigned int *)pwm_bg_mfp_cfgs);
    }
#endif
}

extern void GuilinLcdBackLightStatusRecord(UINT8 status);
extern void GuilinLcdBackLightLevelRecord(UINT8 level);

int oled_panel_mapping_backlight_level(int level)
{
    int brightness_level = 0; //ranges: 0~255

    if (level > 10) {
        level = 10;
    }

    switch(level) {
        case 0:
        case 1:
        case 2:
        case 3:
        case 4:
        case 5:
        case 6:
        case 7:
        case 8:
        case 9:
            brightness_level = level * 25;
            break;
        case 10:
            brightness_level = 0xFF;//255
            break;
        default:
            brightness_level = 0;
            break;
    }

    return brightness_level;
}

void lcd_backlight_ctrl(int level)
{
#if USE_LCD_PANEL_ICNA3310_MIPI
    int panel_type = 1;
    int backlight_status = (level > 0) ? 1: 0;
    int backlight_level = oled_panel_mapping_backlight_level(level);
    extern void isca3310_set_display_brightness(int level);
    isca3310_set_display_brightness(backlight_level);
    mipi_panel_save_backlight(panel_type, backlight_status, backlight_level);//save backlight for silent reset
    return;
#endif

#if USE_LCD_PANEL_RM69330_MIPI
    int panel_type = 1;
    int backlight_status = (level > 0) ? 1: 0;
    int backlight_level = oled_panel_mapping_backlight_level(level);
    extern void rm69330_set_display_brightness(int level);
    rm69330_set_display_brightness(backlight_level);
    mipi_panel_save_backlight(panel_type, backlight_status, backlight_level);//save backlight for silent reset
    return;
#endif

#if USE_LCD_PANEL_ILI9806E_MIPI
    int panel_type = 1;
    int backlight_status = (level > 0) ? 1: 0;
    int backlight_level = level;
    backlight_pwm(level);
    mipi_panel_save_backlight(panel_type, backlight_status, backlight_level);//save backlight for silent reset
    return;
#endif

    int pm_type = pmic_get_type();

    if (pm_type == PM_812) { // PM812
        mfp_config((unsigned int *)pm812_bg_mfp_cfgs);
        gpio_set_direction(GPIO77, GPIO_OUT);
        if (level > 0) {
            gpio_output_set(GPIO77, 1);
        }
        else {
            gpio_output_set(GPIO77, 0);
        }
    }
    else if (pm_type == PM_813) {  // PM813
        extern void NingboLcdBackLightCtrl(UINT8 level); //should be 0~5;
        NingboLcdBackLightCtrl(level);
    }
    else if (pm_type == PM_802) {  // PM802
        mfp_config((unsigned int *)pm802_bg_mfp_cfgs);
        gpio_set_direction(GPIO84, GPIO_OUT);
        if (level > 0) {
            gpio_output_set(GPIO84, 1);
        }
        else {
            gpio_output_set(GPIO84, 0);
        }
        GuilinLcdBackLightStatusRecord(level>0?1:0);
    }
    else if (pm_type == PM_803) {  // PM803
        backlight_pwm(level);
        GuilinLcdBackLightStatusRecord(level>0?1:0);
        GuilinLcdBackLightLevelRecord(level);
    }
    else {
        printf("unknown PMIC, lcd_backlight_ctrl failed.\n");
    }
}

#define PMU_SD_ROT_WAKE_CLR 0xD428287C
#define VBUS_DETECT (1 << 15)
bool usb_is_connected(void)
{
    unsigned val = readl(PMU_SD_ROT_WAKE_CLR);
    return ((val & VBUS_DETECT) != 0);
}

int is_chip_3603(void)
{
    uint32_t chip_id = readl(0xD4282C00) & 0xFFFF;
    return ((chip_id == 0x3603) ? 1 : 0);
}
